home *** CD-ROM | disk | FTP | other *** search
Korn shell script | 1997-08-26 | 7.8 KB | 237 lines |
- #!/bin/ksh
- # @(#) chfssize.ksh 1.3 95/10/14
- # Note: this program requires the extra utilities 'asc' and 'chr';
- # asc requires gawk 2.15.5 or later. They should be available here:
- # ftp://ftp.armory.com/pub/scripts/asc
- # ftp://ftp.armory.com/pub/scripts/chr
- # ftp://ftp.armory.com/pub/scobins/gawk (SCO binary)
- # 94/10/15 john h. dubois iii (john@armory.com)
- # 95/08/02 Added 0 option for oldsize, and p option.
- # 95/08/30 Added reporting of division size, and 0 option for newsize
- # 95/10/14 Run fsck -y -ofull for HTFS filesystems.
-
- lngname=${0##*/}
- Usage="Usage: $lngname [-hrpf] <device-name> [<oldsize> <newsize>]"
- NoReduce=true
- Run_fsck=false
- debug=false
- PrintCommand=false
-
- while getopts :hrpfx opt; do
- case $opt in
- h)
- echo \
- "$lngname: change AFS or EAFS filesystem size.
- $lngname increases the size of a filesystem by increasing the value of the
- fsize field in the filesystem superblock. This should only be done after
- modifying the divvy table to allocate extra space to a filesystem by increasing
- the value of the 'Last Block'. This is only possible if there is space
- available on the partition after the filesystem. The size of a filesystem
- should only be increased, not decreased, because there is no facility for
- ensuring that no blocks are used at the end of the filesystem.
- $Usage
- <device-name> is the device the filesystem resides on. The name of the block
- device should be given, e.g. /dev/u. If only <device-name> is given, the
- current filesystem size is printed. <oldsize> and <newsize> are the current
- and desired sizes of the filesystem, in 1K blocks. <oldsize> must be given as
- a check that the right device and units are being used. If 0 is given for
- <oldsize>, no check is done. This avoids the need for the \"asc\" utility, but
- is more dangerous. If 0 is given for <newsize>, the current division size is
- used.
- This utility only patches the fsize field. It does not do anything to add
- the newly included blocks to the filesystem. To do that, you must run
- fsck -s <block-device-name>
- after this program completes succesfully. NOTE that patching the superblock is
- intrinsically dangerous and should only be done after a level-0 backup of a
- filesystem. This utility has been tested on EAFS filesystems, and minimally
- tested on HTFS filesystems. It should also work on AFS filesystems. It should
- never be used on a mounted filesystem. To change the size of the root
- filesystem, boot from a boot/root set or another division, or boot with the
- root filesystem mounted read-only (use the ronly boot parameter). The -p
- option can be used to generate a command to issue when booting from a
- boot/root set.
- Example:
- $lngname /dev/u 1000000 1116000
- Options:
- -h: Print this help.
- -p: Instead of changing the filesystem size, show a simple echo-to-dd command
- that would change the filesystem size. This can be used to generate a
- command that can be used on another system or e.g. when booting in a manner
- that does not allow this utility to be used directly. Use of this option
- changes all error checks to warnings.
- -f: Run 'fsck -s' (for EAFS) or 'fsck -y -ofull' (for HTFS) on the device after
- changing its size.
- -r: Reduce the size of a filesystem. Without this option, $lngname will refuse
- to let the size be made smaller than it currently is. This option might
- be used if a filesystem was expanded and then needed to be restored to its
- original size without it ever having been mounted. It should NOT be used
- on an HTFS filesystem except specifically to restore the size of a
- filesystem that was increased in size with this utility."
- exit 0
- ;;
- x)
- debug=true
- ;;
- f)
- Run_fsck=true
- ;;
- r)
- NoReduce=false
- ;;
- p)
- PrintCommand=true
- ;;
- +?)
- print -u2 "$lngname: options should not be preceded by a '+'."
- exit 1
- ;;
- :)
- print -r -u2 -- \
- "$lngname: Option '$OPTARG' requires a value. Use -h for help."
- exit 1
- ;;
- ?)
- print -u2 "$lngname: $OPTARG: bad option. Use -h for help."
- exit 1
- ;;
- esac
- done
-
- $debug && set -x
-
- # remove args that were options
- let OPTIND=OPTIND-1
- shift $OPTIND
-
- if [ $# -eq 0 -o $# -eq 2 -o $# -gt 3 ]; then
- print -u2 "$Usage\nUse -h for help."
- exit
- fi
-
- # Usage: GetMajMin device-name ...
- # Prints the major #, minor #, and name of each device, one set per line.
- # or nothing if the path is not a device. Output lines are not neccessarily in
- # the same order as the parameters.
- # Returns 1 if no names were devices, else 0.
- function GetMajMin {
- # l -gon output looks like this:
- # 1 2 3 4 5
- # br--r----- 1 1, 40 Aug 10 18:26 /dev/root
- typeset IFS=" ," maj min
- typeset -i exitVal=1
-
- l -gon -- "$@" | while read line; do
- set -- $line
- [[ $# -lt 8 || "$3" != +([0-9]) || "$4" != +([0-9]) ]] && continue
- maj=$3
- min=$4
- shift 7
- print -r "$maj $min $*"
- exitVal=0
- done
- return $exitVal
- }
-
- # Usage: DivInfo device-name
- # Prints starting block, ending block, size, major #, minor #, div #, name
- # Returns 0 on success, 1 if the given file was not a device, 2 if it is not
- # on a UNIX partition, 3 if it is the whole partition (not a division),
- # 4 if it is not a divvied device.
- function DivInfo {
- typeset -i Division maj min divnum start end Part
- typeset name Device=$1
-
- GetMajMin "$Device" | read maj min name || return 1
- Division=min%8
- Part=min/8%8
- [ Part -lt 1 -o Part -gt 5 ] && return 2
- [ Division -eq 7 ] && return 3
-
- # This assumes we can run divvy on a division and have it operate on the
- # partition that the division is in.
- /etc/divvy -P $Division | read divnum start end || return 4
- print -r "$start $end $((end-start+1)) $maj $min $Division $Device"
- return 0
- }
-
- function Error {
- if $PrintCommand; then
- print -u2 "$lngname: WARNING: $*"
- else
- print -u2 "$lngname: FATAL ERROR: $*"
- exit 1
- fi
- }
-
- Device=$1
-
- [ ! -b "$Device" ] && Error "$Device: not a block device."
- DivInfo "$Device" | read st en DivSize other ||
- Error "Could not get size of division $Device"
-
- $PrintCommand || set -e # for extra safety
-
- # Do this if EITHER we must have the information, or the command exists.
- # If we must have the info and the command isn't found, we will exit due to
- # -e being set.
- if [ "$2" != 0 ] || type asc > /dev/null 2>&1; then
- dd bs=4 iseek=129 count=1 if="$Device" 2>/dev/null | asc -l | read blocks
- fi
-
- if [ $# -ne 3 ]; then
- print "$lngname: Current size of filesystem on $Device: $blocks blocks."
- print "$lngname: Current size of division $Device: $DivSize blocks."
- exit 0
- fi
-
- [ -n "$blocks" ] && print "Old filesystem size: $blocks blocks."
-
- [ 0 != "$2" -a "$blocks" -ne "$2" ] && Error \
- "fs size ($blocks blocks) doesn't match given value ($2 blocks)"
-
- typeset -i NewSize
- if [ 0 = "$3" ]; then
- NewSize=DivSize
- print "New filesystem size (division size): $NewSize blocks."
- else
- NewSize=$3
- [ -n "$DivSize" -a "$DivSize" -ne NewSize ] &&
- print \
- "Note: new filesystem size is not the same as the current division size."
- fi
-
- if [ NewSize -lt "$2" ] && $NoReduce; then
- Error \
- "New fs size ($NewSize blocks) is smaller than old size ($2 blocks).
- Use the -r option if you really want to reduce the fs size (dangerous)."
- fi
-
- if $PrintCommand; then
- # Use -r because chr will emit escape codes
- print -r \
- "Issue the following command to change the size of $Device.
- WARNING: No sanity checks will be done at the time you issue this command!!!
- echo \"$(chr -e -l4 "$NewSize")\" | dd bs=4 count=1 oseek=129 of=$Device"
-
- else
- chr -l4 "$NewSize" | dd bs=4 count=1 oseek=129 of="$Device" 2>/dev/null
- if $Run_fsck; then
- fstype=$(/etc/fstyp $Device)
- case "$fstype" in
- EAFS)
- fsckCmd="fsck -s $Device"
- ;;
- HTFS)
- fsckCmd="fsck -y -ofull $Device"
- ;;
- *)
- print -u2 \
- "Filesystem type is '$fstype'; only know what arguments
- to give fsck for EAFS or HTFS filesystems. fsck not run."
- exit 1
- esac
- print "Running '$fsckCmd'"
- $fsckCmd
- fi
- fi
-